﻿/*
 * Created by SharpDevelop.
 * User: Administrator
 * Date: 3/1/2011
 * Time: 8:30 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using TomatoSynchronizer.Entities;
using TomatoSynchronizer.Store;
using HtmlAgilityPack;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace TomatoSynchronizer.Synchronizer
{
	/// <summary>
	/// Description of WeightClassSynchronizer
	/// </summary>
	public static class WeightClassSynchronizer
	{
		public static void Synchronize(Site siteSrc,Site siteDest,HtmlWeb client,SyncDirection direction)
		{
			switch(direction)
			{
				case SyncDirection.Download:
					UpLoadItems(siteDest,siteSrc,client,direction);
					break;
				case SyncDirection.Upload:
					UpLoadItems(siteSrc,siteDest,client,direction);
					break;
				case SyncDirection.DownloadAndUpload:
					UpLoadItems(siteDest,siteSrc,client,SyncDirection.Download);
					UpLoadItems(siteSrc,siteDest,client,SyncDirection.Upload);
					break;
				case SyncDirection.UploadAndDownload:
					UpLoadItems(siteSrc,siteDest,client,SyncDirection.Upload);
					UpLoadItems(siteDest,siteSrc,client,SyncDirection.Download);
					break;
				case SyncDirection.Synchronize:
					WeightClassStore WeightClassStoreDest = new WeightClassStore(siteDest,client);
					
					WeightClass[] WeightClasssDest =  WeightClassStoreDest.LoadItems();
					
					foreach(WeightClass WeightClassDest in WeightClasssDest)
					{												
						if(!WeightClassDest.is_default)
						{
							bool deleted = WeightClassStoreDest.DeleteItem(WeightClassDest.weight_class_id);
							if(!deleted)
							{
								throw new Exception("Could not delete the WeightClass " + WeightClassDest.weight_class_title);
							}
						}
					}
					
					UpLoadItems(siteSrc,siteDest,client,SyncDirection.Upload);										
					break;
			}
		}
		
		private static void UpLoadItems(Site _siteSrc,Site _siteDest,HtmlWeb client,SyncDirection direction)
		{
			WeightClassStore WeightClassStoreSrc = new WeightClassStore(_siteSrc,client);
			WeightClassStore WeightClassStoreDest = new WeightClassStore(_siteDest,client);
			
			WeightClass[] WeightClasssSrc =  WeightClassStoreSrc.LoadItems();
			WeightClass[] WeightClasssDest =  WeightClassStoreDest.LoadItems();
			
			MappingStore mappingStoreSrc = new MappingStore(_siteSrc,_siteDest,"weight_class_id");
			MappingStore mappingStoreDest = new MappingStore(_siteDest,_siteSrc,"weight_class_id");
			
			mappingStoreSrc.Clean<WeightClass>(WeightClassStoreSrc,WeightClassStoreDest);
			mappingStoreDest.Clean<WeightClass>(WeightClassStoreDest,WeightClassStoreSrc);
			
			MappingStore mappingStore = new MappingStore(_siteSrc,_siteDest,"languages_id");
			
			List<WeightClass> alreadySynchronized = new List<WeightClass>();
			
			foreach(WeightClass WeightClassSrc in WeightClasssSrc)
			{
				//we assume the WeightClass is not yet synchronized
				bool synchronized = false;
				
				//we check if a mapping already exists for this WeightClass in the destination store
				foreach(Mapping mapping in mappingStoreSrc.Mappings)
				{
					if(mapping.SrcValue == WeightClassSrc.weight_class_id && synchronized == false)
					{
						if(!string.IsNullOrEmpty(mapping.DestValue))
						{
							//this WeightClass already exists in the destination store
							//we check if everything changed since the last synchronization
							WeightClass WeightClassDest = WeightClassStoreDest.GetItem(mapping.DestValue);
							if(!string.IsNullOrEmpty(WeightClassDest.weight_class_id))
							{
								synchronized = SynchronizeItem(WeightClassSrc,WeightClassDest);
							}
							else
							{
								//the mapping exists, but the WeightClass has been deleted in the destination store
								//we set a flag that this mapping does not exists anymore
								mapping.Exists = false;
							}
						}
					}
				}
				
				if(!synchronized)
				{
					//there is no mapping, we check if this WeightClass already exists in the destination store
					foreach(WeightClass WeightClassDest in WeightClasssDest)
					{
						foreach(Mapping mapping in mappingStore.Mappings)
						{
							try
							{
								if(WeightClassSrc.keys["key[" + mapping.SrcValue + "]"] == WeightClassDest.keys["key[" + mapping.DestValue + "]"] && synchronized == false && !alreadySynchronized.Contains(WeightClassSrc))
								{
									//we get the 2 currencies from sites to get sure they really exist
									WeightClass src = WeightClassSrc.Store.GetItem(WeightClassSrc.weight_class_id);
									WeightClass dest = WeightClassDest.Store.GetItem(WeightClassDest.weight_class_id);
									
									if(src != null)
									{
										if(dest.weight_class_id != null)
										{
											Mapping _mapping = new Mapping(WeightClassSrc.weight_class_id,WeightClassDest.weight_class_id,"weight_class_id");
											mappingStoreSrc.Mappings.Add(_mapping);
											
											synchronized = SynchronizeItem(WeightClassSrc,WeightClassDest);
										}
										else
										{
											synchronized = false;
										}
									}
									else
									{
										synchronized = true;
									}
								}
							}
							catch (KeyNotFoundException)
							{
								
							}
						}
						
					}
				}
				
				if(!synchronized)
				{
					//no mapping the WeightClass is new
					//we insert it in the destination store
					string remoteId = string.Empty;										
					
					Dictionary<string, string> _keys = new Dictionary<string, string>();
					Dictionary<string, string> _names = new Dictionary<string, string>();
					
					foreach(Mapping mapping in mappingStore.Mappings)
					{
						_keys["key[" + mapping.DestValue + "]"] = WeightClassSrc.keys["key[" + mapping.SrcValue + "]"];
						_names["name[" + mapping.DestValue + "]"] = WeightClassSrc.names["name[" + mapping.SrcValue + "]"];
					}

					var wclassesDest = WeightClassStoreDest.LoadItems();
					var wclassesSrc = WeightClassSrc.Store.LoadItems();
					List<WeightClassRule> rules = new List<WeightClassRule>();
					
					foreach(WeightClassRule _rule in WeightClassSrc.rules)
					{
						foreach(WeightClass wclassDest in wclassesDest)
						{
							if(_rule.weight_class_title == wclassDest.weight_class_title)
							{
								_rule.weight_class_id = wclassDest.weight_class_id;
								rules.Add(_rule);
							}
						}
					}
					
					var oldRules = WeightClassSrc.rules;
					var oldKeys = WeightClassSrc.keys;
					var oldNames = WeightClassSrc.names;
					var oldLangId = WeightClassSrc.language_id;
					
					WeightClassSrc.rules = rules.ToArray();
					WeightClassSrc.keys = _keys;
					WeightClassSrc.names = _names;
					
					//we set the language_id of the dest WeightClass
					//we set the new keys and names based on the dest language_ids
					WeightClassSrc.language_id = WeightClassStoreDest.Default_language_id;
					
					if(WeightClassSrc.language_id == oldLangId)
					{
						throw new Exception("Could not set the default language_id for the WeightClass " + WeightClassSrc.weight_class_title + " in site " + WeightClassStoreDest.site.Name);
					}
					
					remoteId = WeightClassStoreDest.InsertItem(WeightClassSrc);
					
					synchronized = remoteId != string.Empty;
					
//						synchronized = true;
					
					if(!synchronized)
					{
						throw new Exception("The WeightClass " + WeightClassSrc.weight_class_title + " has not been synchronized");
					}
					
					//we reset the WeightClassSrc
					WeightClassSrc.rules = oldRules;
					WeightClassSrc.keys = oldKeys;
					WeightClassSrc.names = oldNames;
					WeightClassSrc.language_id = oldLangId;
					
					Mapping _mapping = new Mapping(WeightClassSrc.weight_class_id,remoteId,"weight_class_id");
					mappingStoreSrc.Mappings.Add(_mapping);
					synchronized = true;
				}
				
				if(!synchronized)
				{
					throw new Exception("could not synchronize the WeightClass " + WeightClassSrc.weight_class_title);
				}
				
				WeightClassStoreSrc.PersistItem(WeightClassSrc);
				alreadySynchronized.Add(WeightClassSrc);
			}
			
			mappingStoreSrc.Save();
			
			mappingStoreDest.Truncate();
			
			//we save the mappings in the destination MappingStore too
			foreach(Mapping mapping in mappingStoreSrc.Mappings)
			{
				if(mapping.Exists)
				{
					Mapping mappingDest = new Mapping(mapping.DestValue,mapping.SrcValue,mapping.Property);
					mappingStoreDest.Mappings.Add(mappingDest);
				}
			}
			
			mappingStoreDest.Save();
			
			//we check if the 2 MappingStore are synchronized
			if(mappingStoreSrc.Mappings.Count != mappingStoreDest.Mappings.Count)
			{
				throw new Exception("The mapping store are not synchronized");
			}
		}				
		
		private static bool SynchronizeItem(WeightClass WeightClassSrc,WeightClass WeightClassDest)
		{
			bool synchronized = true;
			
			if(!WeightClassSrc.Equals(WeightClassDest))
			{
				synchronized = false;
				
				//we update the destination WeightClass
				WeightClassSrc.language_id = WeightClassDest.language_id;
				WeightClassSrc.weight_class_id = WeightClassDest.weight_class_id;
				
				var languages = WeightClassDest.Store.site.GetLanguageStore().LoadItems();
				
				Dictionary<string, string> _keys = new Dictionary<string, string>();
				Dictionary<string, string> _names = new Dictionary<string, string>();
				
				MappingStore mappingStore = new MappingStore(WeightClassSrc.Store.site,WeightClassDest.Store.site,"languages_id");
				foreach(Mapping mapping in mappingStore.Mappings)
				{
					_keys["key[" + mapping.DestValue + "]"] = WeightClassSrc.keys["key[" + mapping.SrcValue + "]"];
					_names["name[" + mapping.DestValue + "]"] = WeightClassSrc.names["name[" + mapping.SrcValue + "]"];
				}
				
				var wclassesDest = WeightClassDest.Store.LoadItems();
				var wclassesSrc = WeightClassSrc.Store.LoadItems();
				
				List<WeightClassRule> rules = new List<WeightClassRule>();
				foreach(WeightClassRule _rule in WeightClassSrc.rules)
				{
					foreach(WeightClass wclassDest in wclassesDest)
					{
						if(_rule.weight_class_title == wclassDest.weight_class_title)
						{
							_rule.weight_class_id = wclassDest.weight_class_id;
							rules.Add(_rule);
						}
					}
				}
				
				WeightClassSrc.rules = rules.ToArray();
				
				var oldKeys = WeightClassSrc.keys;
				var oldNames = WeightClassSrc.names;
				var oldLangId = WeightClassSrc.language_id;
				
				WeightClassSrc.keys = _keys;
				WeightClassSrc.names = _names;
				
				synchronized = WeightClassDest.Store.UpdateItem(WeightClassSrc);
			}
			
			return synchronized;
		}
		
		private static string UploadItem(WeightClassStore WeightClassStoreDest,WeightClass WeightClass)
		{
			string remoteId = string.Empty;
			
			remoteId = WeightClassStoreDest.InsertItem(WeightClass);
			
			return remoteId;
		}
	}
}
